﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GalaSoft.MvvmLight;
using MusicExplorer.WebRepository;
using MusicExplorer.WebRepository.Service;
using MusicExplorer.Wrappers;
using MusicExplorer.Internals;
using System.Windows.Input;
using GalaSoft.MvvmLight.Command;
using MusicExplorer.WebRepository.Interface;
using System.Net;
using System.Threading;
using MusicExplorer.Helper;
using MusicExplorer.Data.Entities;

namespace MusicExplorer.ViewModel.Popup
{
    public abstract class EntityPreferencesViewModel : ViewModelBase, IDisposable
    {
        public EntityPreferencesViewModel(MainWindowViewModel parent)
        {
            m_enableEntities = new ObservableCollection<DetailTreeItemWrapper>();
            m_disableEntities = new ObservableCollection<DetailTreeItemWrapper>();

            m_searchedEntitiesLog = new LogViewModel(parent);
            m_searchedEntitiesToAdd = new ObservableCollection<DetailTreeItemWrapper>();
            m_webClientSearchEntity = new WebClient();
            m_tokenSearchEntity = new CancellationTokenSource();
        }

        public abstract bool CanAddEntity { get; }

        public abstract string EntityName { get; }

        public abstract string EntityPluralName { get; }

        public string DisplayTitle { get { return EntityPluralName + " management"; } }

        public string ManagementTabTitle { get { return EntityPluralName + " management"; } }

        public string NewEntityTabTitle { get { return "Add new " + EntityName; } }

        public virtual void UpdateEntities()
        {
            for (int i = 0; i < m_enableEntities.Count; i++)
            {
                m_enableEntities[i].Entity.Order = i;
                m_enableEntities[i].Entity.Visible = true;
            }

            for (int i = 0; i < m_disableEntities.Count; i++)
            {
                m_disableEntities[i].Entity.Order = -1;
                m_disableEntities[i].Entity.Visible = false;
            }
        }

        #region ADD

        private readonly LogViewModel m_searchedEntitiesLog;
        public LogViewModel SearchedEntitiesLog { get { return m_searchedEntitiesLog; } }

        protected readonly WebClient m_webClientSearchEntity;
        protected CancellationTokenSource m_tokenSearchEntity;
        protected Task m_taskSearchEntity;
        protected int m_currentPageSearch;

        #region ADD PROPERTIES

        protected string m_currentSearchTerms;
        private string m_searchTerms;
        public string SearchTerms
        {
            get { return m_searchTerms; }
            set
            {
                if (m_searchTerms != value)
                {
                    m_searchTerms = value;
                    SearchTerms = value;
                }
            }
        }

        protected DetailTreeItemWrapper m_selectedEntityToAdd;
        public DetailTreeItemWrapper SelectedEntityToAdd
        {
            get { return m_selectedEntityToAdd; }
            set
            {
                if (m_selectedEntityToAdd != value)
                {
                    m_selectedEntityToAdd = value;
                    RaisePropertyChanged("SelectedEntityToAdd");
                }
            }
        }

        private ObservableCollection<DetailTreeItemWrapper> m_searchedEntitiesToAdd;
        public ObservableCollection<DetailTreeItemWrapper> SearchedEntitiesToAdd
        {
            get { return m_searchedEntitiesToAdd; }
            set
            {
                if (m_searchedEntitiesToAdd != value)
                {
                    m_searchedEntitiesToAdd = value;
                    RaisePropertyChanged("SearchedEntitiesToAdd");
                }
            }
        }

        #endregion

        #region ADD COMMANDS

        protected bool m_nothingToSearch;
        public ICommand SearchEntityCommand
        {
            get
            {
                return new RelayCommand(() =>
                    {
                        if (!String.IsNullOrEmpty(m_searchTerms))
                        {
                            m_nothingToSearch = false;
                            m_currentSearchTerms = m_searchTerms;

                            SelectedEntityToAdd = null;
                            SearchedEntitiesToAdd.Clear();

                            m_tokenSearchEntity.Cancel();
                            m_webClientSearchEntity.CancelAsync();

                            if (m_taskSearchEntity != null)
                            {
                                // This task has cancel pending and stop in few ms
                                m_taskSearchEntity.Wait();
                            }

                            m_tokenSearchEntity = new CancellationTokenSource();

                            m_currentPageSearch = 1;
                            m_taskSearchEntity = Task.Factory.StartNew(() => SearchEntityFromTerms());
                        }
                    }, () => !String.IsNullOrEmpty(m_searchTerms));
            }
        }

        protected abstract bool SearchEntityFromTerms();

        #region SCROLL VIEWER

        private ScrollViewerState m_scrollViewerState;
        public ScrollViewerState ScrollViewerState
        {
            get { return m_scrollViewerState; }
            set
            {
                m_scrollViewerState = value;
                if (m_taskSearchEntity != null && m_taskSearchEntity.IsCompleted)
                    LaunchTaskFromScrollViewerState();
            }
        }

        public void LaunchTaskFromScrollViewerState()
        {
            if (m_scrollViewerState.HeightArea > 0 && !m_nothingToSearch)
            {
                if (m_scrollViewerState.ScrollableHeight == 0 ||
                    m_scrollViewerState.ScrollableHeight - m_scrollViewerState.CurrentScroll < 10)
                {
                    m_currentPageSearch++;
                    m_taskSearchEntity = Task.Factory.StartNew(() => SearchEntityFromTerms());
                }
            }
        }

        #endregion

        public ICommand AddEntityCommand
        {
            get
            {
                return new RelayCommand(() =>
                {
                    EnableEntities.Add(m_selectedEntityToAdd);
                    SearchedEntitiesToAdd.Remove(m_selectedEntityToAdd);
                }, () => m_selectedEntityToAdd != null);
            }
        }

        public ICommand RemoveEntityCommand
        {
            get
            {
                return new RelayCommand(() =>
                {
                    DisableEntities.Remove(m_selectedDisableEntity);
                }, () => m_selectedDisableEntity != null);
            }
        }
        #endregion

        #endregion

        #region ORDER
        #region ORDER PROPERTIES

        private DetailTreeItemWrapper m_selectedEnableEntity;
        public DetailTreeItemWrapper SelectedEnableEntity
        {
            get { return m_selectedEnableEntity; }
            set
            {
                if (m_selectedEnableEntity != value)
                {
                    m_selectedEnableEntity = value;
                    RaisePropertyChanged("SelectedEnableEntity");
                }
            }
        }

        private DetailTreeItemWrapper m_selectedDisableEntity;
        public DetailTreeItemWrapper SelectedDisableEntity
        {
            get { return m_selectedDisableEntity; }
            set
            {
                if (m_selectedDisableEntity != value)
                {
                    m_selectedDisableEntity = value;
                    RaisePropertyChanged("SelectedDisableEntity");
                }
            }
        }

        protected ObservableCollection<DetailTreeItemWrapper> m_enableEntities;
        public ObservableCollection<DetailTreeItemWrapper> EnableEntities { get { return m_enableEntities; } }

        protected ObservableCollection<DetailTreeItemWrapper> m_disableEntities;
        public ObservableCollection<DetailTreeItemWrapper> DisableEntities { get { return m_disableEntities; } }

        public IEnumerable<DetailTreeItemWrapper> Entities { get { return m_enableEntities.Union(m_disableEntities); } }

        #endregion

        #region ORDER COMMANDS

        public ICommand UpEntityCommand
        {
            get {
                return new RelayCommand(() =>
                {
                    UpSelectedEntity();
                }, () => (SelectedEnableEntity != null && EnableEntities.IndexOf(SelectedEnableEntity) > 0));
            }
        }

        public ICommand DownEntityCommand
        {
            get
            {
                return new RelayCommand(() =>
                {
                    DownSelectedEntity();
                }, () => (SelectedEnableEntity != null && EnableEntities.IndexOf(SelectedEnableEntity) < EnableEntities.Count - 1));
            }
        }

        public ICommand DisableEntityCommand
        {
            get
            {
                return new RelayCommand(() =>
                {
                    DisableSelectedEntity();
                }, () => SelectedEnableEntity != null);
            }
        }

        public ICommand EnableEntityCommand
        {
            get
            {
                return new RelayCommand(() =>
                {
                    EnableSelectedEntity();
                }, () => SelectedDisableEntity != null);
            }
        }

        #endregion

        #region FUNCTIONS

        private void UpSelectedEntity()
        {
            var entityToProcess = SelectedEnableEntity;
            var index = EnableEntities.IndexOf(entityToProcess);
            EnableEntities.Remove(SelectedEnableEntity);
            EnableEntities.Insert(index - 1, entityToProcess);
            SelectedEnableEntity = entityToProcess;
        }

        private void DownSelectedEntity()
        {
            var entityToProcess = SelectedEnableEntity;
            var index = EnableEntities.IndexOf(entityToProcess);
            EnableEntities.Remove(SelectedEnableEntity);
            EnableEntities.Insert(index, entityToProcess);
            SelectedEnableEntity = entityToProcess;
        }

        private void EnableSelectedEntity()
        {
            var entityToProcess = SelectedDisableEntity;
            DisableEntities.Remove(SelectedDisableEntity);
            EnableEntities.Add(entityToProcess);
            SelectedDisableEntity = null;
            SelectedEnableEntity = entityToProcess;
        }

        private void DisableSelectedEntity()
        {
            var entityToProcess = SelectedEnableEntity;
            EnableEntities.Remove(SelectedEnableEntity);
            DisableEntities.Add(entityToProcess);
            SelectedEnableEntity = null;
            SelectedDisableEntity = entityToProcess;
        }

        #endregion
        #endregion

        public void Dispose()
        {
            m_webClientSearchEntity.Dispose();
            m_tokenSearchEntity.Dispose();
        }
    }
}
